package com.project.im.sdk.socket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.SmartLifecycle;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Component
public class ImServerBootstrap implements SmartLifecycle {

    @Value("${netty.port:8081}")
    private int port;
    private NioEventLoopGroup bossGroup;
    private NioEventLoopGroup workerGroup;
    private Channel serverChannel;
    private final AtomicBoolean started = new AtomicBoolean(false);
    private final LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);

    public void doStart() {
        if (!started.compareAndSet(false, true)) {
            log.error("netty服务器已经启动，请勿重复开启...");
            return;
        }
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("netty server");
        ServerBootstrap bootstrap = new ServerBootstrap();
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        InetSocketAddress localAddress = new InetSocketAddress(port);
        try {
            // 服务端配置
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(LOGGING_HANDLER);
                            pipeline.addLast("idleStateHandler", new IdleStateHandler(30, 0, 0, TimeUnit.MINUTES));
                        }
                    });
            serverChannel = bootstrap.bind(localAddress).sync().channel();
            stopWatch.stop();
            log.info("netty服务器启动成功：{} 耗时：{} ms", localAddress, stopWatch.getTotalTimeMillis());
        } catch (InterruptedException e) {
            log.error("netty服务器启动异常：{}", e.getMessage(), e);
        } finally {
            serverChannel.closeFuture().addListener(future -> {
                log.info("准备关闭netty服务端");
                if (bossGroup != null) {
                    bossGroup.shutdownGracefully();
                }
                if (workerGroup != null) {
                    workerGroup.shutdownGracefully();
                }
            });
        }
    }

    public void doStop() {
        started.compareAndSet(true, false);
        if (serverChannel != null) {
            serverChannel.close();
        }
    }

    public Channel getServerChannel() {
        return serverChannel;
    }


    @Override
    public void start() {
        if (!isRunning()) {
            doStart();
        }
    }

    @Override
    public int getPhase() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public boolean isAutoStartup() {
        return true;
    }

    @Override
    public void stop() {
        if (isRunning()) {
            doStop();
        }
    }

    @Override
    public boolean isRunning() {
        return started.get();
    }

}
